package com.baiye.www.handler;

import com.baiye.www.annotation.Controller;
import com.baiye.www.annotation.RequestMapping;
import com.baiye.www.constant.DispatchActionConstant;
import com.baiye.www.context.WebContext;
import com.baiye.www.mapingMap.RequestMapingMap;
import com.baiye.www.utils.ScanClassUtil;
import com.baiye.www.utils.URLUtil;
import com.baiye.www.view.View;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.LinkedHashSet;
import java.util.Set;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: baiye
 * @Date: 2021/07/18/14:50
 * @Description:
 */
public class AnnotationHandleServlet extends HttpServlet {
    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);

        String scanPackage = config.getInitParameter("basePackage");
        initRequestMapingMap(scanPackage);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        execute(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        execute(req, resp);
    }
    private void execute(HttpServletRequest req,HttpServletResponse resp) {
        WebContext.requestHolders.set(req);
        WebContext.responseHolders.set(resp);
        String mappingUrl = URLUtil.pareRequestURI(req);
        Class<?> aClass = RequestMapingMap.requestMap.get(mappingUrl);
        try {
            Object classInstance = aClass.newInstance();
            Method[] declaredMethods = aClass.getDeclaredMethods();
            Method method = null;
            for(Method m:declaredMethods){
                if (m.isAnnotationPresent(RequestMapping.class)) {
                    String value = m.getAnnotation(RequestMapping.class).value();
                    if (value != null && !"".equals(value.trim()) && mappingUrl.equals(value.trim())) {
                        //找到要执行的目标方法
                        method = m;
                        break;
                    }

                }
            }
            Object invoke = null;
            if(method!=null){
                invoke = method.invoke(classInstance);
            }
            if(invoke!=null){
                View view = (View) invoke;
                if(view.getDisPathAction().equals(DispatchActionConstant.FORWARD)){
                    req.getRequestDispatcher(view.getUrl()).forward(req,resp);
                }else if(view.getDisPathAction().equals(DispatchActionConstant.REDIRECT)){
                    resp.sendRedirect(req.getContextPath() + view.getUrl());
                }
            }

        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void initRequestMapingMap(String packageName){
        Set<Class<?>> classSet = ScanClassUtil.getClasses(packageName);
        for (Class clazz:classSet) {
            if (clazz.isAnnotationPresent(Controller.class)){
                Method[] declaredMethods = clazz.getDeclaredMethods();
                for (Method method:declaredMethods) {
                    if(method.isAnnotationPresent(RequestMapping.class)){
                        String mappingValue = method.getAnnotation(RequestMapping.class).value();
                        if(mappingValue != null&&!"".equals(mappingValue.trim())){
                            if(RequestMapingMap.requestMap.containsKey(mappingValue)){
                                throw new RuntimeException("RequestMapping不能重复");
                            }
                            RequestMapingMap.requestMap.put(mappingValue,clazz);
                        }
                    }
                }
            }
        }
    }
}
